Zap
Time Limit: 10 Sec Memory Limit: 162 MB
Description
对于给定的整数a,b和d,有多少正整数对x,y,满足x<=a,y<=b,并且gcd(x,y)=d。
第一行包含一个正整数n,表示一共有n组询问。接下来n行,每行表示一个询问,每行三个正整数,分别为a,b,d。
Output
输出一个正整数,表示满足条件的整数对数。
2
4 5 2
6 4 3
Sample Output
3
2
HINT
1<=n<= 50000, 1<=d<=a,b<=50000
Solution
我们运用莫比乌斯反演,然后推一下式子得到:
我们依旧对于下界分块求解即可。
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
| #include<bits/stdc++.h> using namespace std; typedef long long s64;
const int ONE = 50005;
int T; int n,m,k; bool isp[ONE]; int prime[ONE],p_num; int miu[ONE],sum_miu[ONE]; s64 Ans;
int get() { int res=1,Q=1; char c; while( (c=getchar())<48 || c>57) if(c=='-')Q=-1; if(Q) res=c-48; while((c=getchar())>=48 && c<=57) res=res*10+c-48; return res*Q; }
void Getmiu(int MaxN) { miu[1] = 1; for(int i=2; i<=MaxN; i++) { if(!isp[i]) prime[++p_num] = i, miu[i] = -1; for(int j=1; j<=p_num, i*prime[j]<=MaxN; j++) { isp[i * prime[j]] = 1; if(i%prime[j] == 0) { miu[i * prime[j]] = 0; break; } miu[i * prime[j]] = -miu[i]; } miu[i] += miu[i-1]; } }
void Solve() { n=get(); m=get(); k=get(); if(n > m) swap(n,m);
int N = n/k, M = m/k; Ans = 0; for(int i=1,j=0; i<=N; i=j+1) { j = min(N/(N/i), M/(M/i)); Ans += (s64)(N/i) * (M/i) * (miu[j] - miu[i-1]); }
printf("%lld\n",Ans); }
int main() { Getmiu(ONE-1); T=get(); while(T--) Solve(); }
|